package com.tjcd.project.library_base.common.utils;

import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import lombok.Setter;

/**
 * @Author jiangKunKun
 * @CreateDate 2025/2/14
 * @Description rxjava版循环 可暂停和重置
 * @SpittingGrooves
 */
public class ControlledLoop implements Disposable{
    /**
     * 用于管理异步操作的 disposable 对象，以便于后续进行取消操作
     */
    private Disposable disposable;
    /**
     * 标记异步操作是否已被取消
     */
    private boolean isDisposed = false;
    /**
     * 标记异步操作是否处于暂停状态
     */
    private boolean isPaused = false;
    /**
     * 用于同步操作的锁对象，以确保暂停和恢复操作的安全性
     */
    private final Object pauseLock = new Object();
    /**
     * 待执行的操作，通常是一个实现了 Runnable 接口的匿名内部类或 lambda 表达式
     */
    private Runnable action;
    /**
     * 当异步操作完成时执行的动作，通过 Lombok 的 @Setter 注解提供外部设置
     */
    @Setter
    private Runnable onFinishAction;

    public ControlledLoop(Runnable action) {
        this.action = action;
    }
    public ControlledLoop(Runnable action, Runnable onFinishAction) {
        this.action = action;
        this.onFinishAction = onFinishAction;
    }

    /**
     * 开始循环任务
     * @param delay 初始延迟时间（毫秒）
     * @param interval 循环间隔（毫秒）
     * @param maxCount 最大循环次数，-1表示无限循环
     */
    public void start(long delay, long interval, int maxCount) {
        if (disposable != null && !disposable.isDisposed()) {
            stop();
        }
        disposable = Observable.interval(delay, interval, java.util.concurrent.TimeUnit.MILLISECONDS)
                .observeOn(Schedulers.io())
                .doOnNext(aLong -> {
                    synchronized (pauseLock) {
                        while (isPaused && !isDisposed) {
                            try {
                                pauseLock.wait();
                            } catch (InterruptedException e) {
                                Thread.currentThread().interrupt();
                            }
                        }
                    }
                    if (!isDisposed) {
                        action.run();
                    }
                })
                .take(maxCount == -1 ? Integer.MAX_VALUE : maxCount)
                .doOnComplete(() -> {
                    if (!isDisposed && onFinishAction != null) {
                        onFinishAction.run();
                    }
                })
                .subscribe();
    }
    /**
     * 开始循环任务
     * @param interval 循环间隔（毫秒）
     * @param maxCount 最大循环次数，-1表示无限循环
     */
    public void start(long interval, int maxCount) {
        start(0, interval, maxCount);
    }

    @Override
    public void dispose() {
        isDisposed = true;
        if (disposable != null) {
            disposable.dispose();
        }
        synchronized (pauseLock) {
            pauseLock.notifyAll(); // 确保唤醒等待中的线程
        }
    }

    @Override
    public boolean isDisposed() {
        return isDisposed;
    }

    /**
     * 暂停循环任务
     */
    public void pause() {
        synchronized (pauseLock) {
            isPaused = true;
        }
    }

    /**
     * 恢复循环任务
     */
    public void resume() {
        synchronized (pauseLock) {
            isPaused = false;
            pauseLock.notifyAll();
        }
    }

    /**
     * 重置循环任务
     * @param delay 新的初始延迟时间（毫秒）
     * @param interval 新的循环间隔（毫秒）
     * @param maxCount 新的最大循环次数，-1表示无限循环
     */
    public void reset(long delay, long interval, int maxCount) {
        dispose();
        // 重置 isDisposed 和 isPaused 标志
        isDisposed = false;
        isPaused = false;
        synchronized (pauseLock) {
            pauseLock.notifyAll(); // 确保唤醒等待中的线程
        }
        start(delay, interval, maxCount);
    }
    /**
     * 重置循环任务
     * @param interval 新的循环间隔（毫秒）
     * @param maxCount 新的最大循环次数，-1表示无限循环
     */
    public void reset(long interval, int maxCount) {
        reset(0, interval, maxCount);
    }

    /**
     * 停止循环任务
     */
    public void stop() {
        if (disposable != null && !disposable.isDisposed()) {
            disposable.dispose();
        }
    }
}
